package cn.uncode.rpc.cluster.loadbalance;

import java.util.List;

import cn.uncode.rpc.cluster.LoadBalance;
import cn.uncode.rpc.common.log.Logger;
import cn.uncode.rpc.common.log.LoggerFactory;
import cn.uncode.rpc.core.Invoker;
import cn.uncode.rpc.core.Request;
import cn.uncode.rpc.exception.ClusterException;



/**
 * 
 * loadbalance
 * 
 * @author fishermen
 * @version V1.0 created at: 2013-5-22
 */

public abstract class AbstractLoadBalance<T> implements LoadBalance<T> {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLoadBalance.class);
	
    public static final int MAX_CALLER_COUNT = 10;

    private List<Invoker<T>> invokers;

    @Override
    public void onRefresh(List<Invoker<T>> invokers) {
        // 只能引用替换，不能进行invokers update。
        this.invokers = invokers;
    }

    @Override
    public Invoker<T> select(Request request) {
        List<Invoker<T>> invokers = this.invokers;

        Invoker<T> ref = null;
        if (invokers.size() > 1) {
            ref = doSelect(request);

        } else if (invokers.size() == 1) {
            ref = invokers.get(0).isAvailable() ? invokers.get(0) : null;
        }

        if (ref != null) {
            return ref;
        }
        throw new ClusterException(this.getClass().getSimpleName() + " No available invokers for call request:" + request);
    }

    @Override
    public void selectToHolder(Request request, List<Invoker<T>> refersHolder) {
        List<Invoker<T>> invokers = this.invokers;

        if (invokers == null) {
            throw new ClusterException(this.getClass().getSimpleName() + " No available invokers for call : invokers_size= 0 ");
        }

        if (invokers.size() > 1) {
            doSelectToHolder(request, refersHolder);

        } else if (invokers.size() == 1 && invokers.get(0).isAvailable()) {
            refersHolder.add(invokers.get(0));
        }
        if (refersHolder.isEmpty()) {
            throw new ClusterException(this.getClass().getSimpleName() + " No available invokers for call : invokers_size="
                    + invokers.size());
        }
    }

    protected List<Invoker<T>> getInvokers() {
        return invokers;
    }
    
    @Override
    public void setWeightString(String weightString) {
    	LOGGER.info("ignore weightString:" + weightString);
    }

    protected abstract Invoker<T> doSelect(Request request);

    protected abstract void doSelectToHolder(Request request, List<Invoker<T>> refersHolder);
}
